<?php
namespace api\common\tools;

class WechatPay{
    // public:权限是最大的，可以内部调用，实例调用等。
    // protected: 受保护类型，用于本类和继承类调用。
    // private: 私有类型，只有在本类中使用。
    private $appid;
    private $openid;
    private $mch_id;
    private $key;
    private $SetOut_trade_no;
    private $total_fee;
    private $pay_body;
    private $notify_url;

    public function __construct($appid,$openid,$mch_id,$key,$SetOut_trade_no,$total_fee,$pay_body,$notify_url){
        $this->appid= $appid; // 小程序开发ID
        $this->openid=$openid; // 微信用于唯一识别号
        $this->mch_id=$mch_id; // 商户号
        $this->key=$key; // 签名KEY
        $this->SetOut_trade_no=$SetOut_trade_no; // 组合订单ID
        $this->total_fee=$total_fee; // 商品价格(分)
        $this->pay_body=$pay_body; // 商品介绍
        $this->notify_url=$notify_url; // 通知结果
    }

    /**
     * 主要使用方法
     * 20170920 YCS
     */
    public function pay(){
        // 统一下单接口
        $return=$this->weixinapp();
        return $return;
    }

    /**
     * 微信小程序接口
     * 20170920 YCS
     */
    private function weixinapp(){
        //统一下单接口
        $unifiedorder=$this->unifiedorder();
        $parameters=array(
                'appId'=>$this->appid,//小程序ID
                'timeStamp'=>''.time().'',//时间戳
                'nonceStr'=>$this->createNoncestr(),//随机串
                'package'=>'prepay_id='.$unifiedorder['prepay_id'],//数据包
                'signType'=>'MD5'//签名方式
                );
        //签名
        $parameters['paySign']=$this->getSign($parameters);
        return $parameters;
    }

    /**
     * 统一下单接口 获取prepay_id
     * 20170920 YCS
     */
    private function unifiedorder(){
        $url='https://api.mch.weixin.qq.com/pay/unifiedorder';
        $parameters=array(
                'appid'=>$this->appid,//小程序ID
                'mch_id'=>$this->mch_id,//商户号
                'nonce_str'=>$this->createNoncestr(),//随机字符串
                'body'=>$this->pay_body,//商品描述
                'out_trade_no'=>$this->SetOut_trade_no,//商户订单号
                'total_fee'=>$this->total_fee,//总金额 单位 分
                'spbill_create_ip'=>$_SERVER['REMOTE_ADDR'],//终端IP
                'notify_url'=>$this->notify_url,//通知地址 (作废)
                'openid'=>$this->openid,//微信用户id
                'trade_type'=>'JSAPI'//交易类型
                );
        //统一下单签名
        $parameters['sign']=$this->getSign($parameters);
        $xmlData = $this->arrayToXml($parameters);
        $return  = $this->xmlToArray($this->postXmlCurl($xmlData,$url,60));
        // dump($return);
        // exit();
        return $return;
    }


    // 以post方式提交xml到对应的接口url
    private function postXmlCurl($xml, $url, $second = 30){
        $ch = curl_init();
        //设置超时
        curl_setopt($ch, CURLOPT_TIMEOUT, $second); // 超时秒
        curl_setopt($ch,CURLOPT_URL, $url);
        curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
        curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);
        //设置header
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        //要求结果为字符串且输出到屏幕上
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        //post提交方式
        curl_setopt($ch, CURLOPT_POST, TRUE);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
        //运行curl
        $data = curl_exec($ch);
        //返回结果
        if($data){
            curl_close($ch);
            return $data;
        } else {
            $error = curl_errno($ch);
            curl_close($ch);
            return false;
        }
    }




    //数组转XML
    private function arrayToXml($arr)
    {
        // dump($arr);
        // exit();

        // $appid            = $arr['appid']; // 小程序ID
        // $mch_id           = $arr['mch_id']; // 商户号
        // $nonce_str        = $arr['nonce_str']; // 随机字符串
        // $sign             = $arr['sign']; // 签名
        // $body             = $arr['body']; // 商品描述
        // $out_trade_no     = $arr['out_trade_no']; // 商户订单号
        // $total_fee        = $arr['total_fee']; // 总金额
        // $spbill_create_ip = $arr['spbill_create_ip']; // 终端IP
        // $notify_url       = $arr['notify_url']; // 通知地址
        // $trade_type       = $arr['trade_type']; // 交易类型
        // $attach           = 'test'; // 附加数据
        //

        $xml = "<xml>";
        foreach ($arr as $key=>$val)
        {
            if (is_numeric($val)){
                $xml.="<".$key.">".$val."</".$key.">";
            }else{
                $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
            }
        }
        $xml.="</xml>";
        return $xml;
        // return $xml;
    }


    //将XML转为array
    private function xmlToArray($xml)
    {
        //禁止引用外部xml实体
        libxml_disable_entity_loader(true);
        $values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $values;
    }

    /**
     * 作用：产生随机字符串，不长于32位
     * 20170920 YCS
     */
    private function createNoncestr($length = 32){
        $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
        $str ="";
        for ($i = 0; $i < $length; $i++) {
            $str.= substr($chars, mt_rand(0, strlen($chars)-1), 1);
        }
        return $str;
    }

    /**
     * 作用：生成签名
     * 20170920 YCS
     */
    private function getSign($Obj){
        foreach ($Obj as $k => $v){
            $Parameters[$k] = $v;
        }
        //签名步骤一：按字典序排序参数
        ksort($Parameters);
        $String = $this->formatBizQueryParaMap($Parameters, false);
        //签名步骤二：在string后加入KEY
        $String = $String."&key=".$this->key;
        //签名步骤三：MD5加密
        $String = md5($String);
        //签名步骤四：所有字符转为大写
        $result_ = strtoupper($String);
        return $result_;
    }

    /**
     * 作用：格式化参数，签名过程需要使用
     * 20170920 YCS
     */
    private function formatBizQueryParaMap($paraMap, $urlencode){
        $buff = "";
        ksort($paraMap);
        foreach ($paraMap as $k => $v){
            if($urlencode){
                $v = urlencode($v);
            }
            $buff .= $k . "=" . $v . "&";
        }
        $reqPar;
        if (strlen($buff) > 0){
            $reqPar = substr($buff, 0, strlen($buff)-1);
        }
        return $reqPar;
    }

}



